<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<svg width="500px" height="500px" viewBox="0 0 500 500">
  <rect width="1" height="1"/>
  <marker markerWidth="1" markerHeight="1"/>
</svg>
<script>
var viewportWidth = 500;
var EPSILON = Math.pow(2, -8);
var cssPixelsPerInch = 96;
var cssPixelsPerCentimeter = cssPixelsPerInch / 2.54; //2.54 cm/in
var cssPixelsPerMillimeter = cssPixelsPerCentimeter / 10;
var cssPixelsPerPoint = cssPixelsPerInch / 72;
var cssPixelsPerPica = cssPixelsPerInch / 6;

function viewportWidthPercent() {
    return viewportWidth / 100;
}

function assert_calc_expression_on_width_attr(expression, expected) {
  var rect = document.querySelector('rect');
  var rectWidth;
  // Test calc with  setAttribute
  rect.setAttribute('width', expression);
  rectWidth = rect.getBoundingClientRect().width;
  assert_approx_equals(rectWidth, expected, EPSILON);
  assert_approx_equals(rect.width.baseVal.value, expected, EPSILON);
  assert_equals(rect.width.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_UNKNOWN);
  assert_equals(rect.width.baseVal.valueInSpecifiedUnits, 0);

  // Test valueInSpecifiedUnits setter after 'calc' value attribute
  rect.width.baseVal.valueInSpecifiedUnits = 100;
  assert_equals(rect.width.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
  assert_equals(rect.width.baseVal.valueInSpecifiedUnits, 100);

  // Test value setter after 'calc' value attribute
  rect.setAttribute('width', expression); // reset to calc value
  rect.width.baseVal.value = 10;
  assert_equals(rect.width.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
  assert_equals(rect.width.baseVal.valueInSpecifiedUnits, 10);

  // Test calc with "valueAsString"
  rect.setAttribute('width', '20px'); // reset to normal value
  rect.width.baseVal.valueAsString = expression;
  assert_approx_equals(rect.width.baseVal.value, expected, EPSILON);
}

function assert_calc_expression_on_markerWidth_attr(expression, expected) {
  var marker = document.querySelector('marker');
  // Test calc with  setAttribute
  marker.setAttribute('markerWidth', expression);
  assert_approx_equals(marker.markerWidth.baseVal.value, expected, EPSILON);
  assert_equals(marker.markerWidth.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_UNKNOWN);
  assert_equals(marker.markerWidth.baseVal.valueInSpecifiedUnits, 0);

  // Test valueInSpecifiedUnits setter after 'calc' value attribute
  marker.markerWidth.baseVal.valueInSpecifiedUnits = 100;
  assert_equals(marker.markerWidth.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
  assert_equals(marker.markerWidth.baseVal.valueInSpecifiedUnits, 100);

  // Test value setter after 'calc' value attribute
  marker.setAttribute('markerWidth', expression); // reset to calc value
  marker.markerWidth.baseVal.value = 10;
  assert_equals(marker.markerWidth.baseVal.unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
  assert_equals(marker.markerWidth.baseVal.valueInSpecifiedUnits, 10);

  // Test calc with "valueAsString"
  marker.setAttribute('markerWidth', '20px'); // reset to normal value
  marker.markerWidth.baseVal.valueAsString = expression;
  assert_approx_equals(marker.markerWidth.baseVal.value, expected, EPSILON);
}

function assert_calc_expression(expression, expected) {
    assert_calc_expression_on_width_attr(expression, expected); // presentation attr
    assert_calc_expression_on_markerWidth_attr(expression, expected); // non presentation attr
}

test(function() {
    assert_calc_expression("calc(20%)", (20 * viewportWidthPercent()));
    assert_calc_expression("calc(10mm + 10in)", (10 * cssPixelsPerMillimeter) + (10 * cssPixelsPerInch));
    assert_calc_expression("calc(10mm + 10mm)", (20 * cssPixelsPerMillimeter));
    assert_calc_expression("calc(20mm)", (20 * cssPixelsPerMillimeter));
    assert_calc_expression("calc(10 + 10)", 20);
    assert_calc_expression("calc(10mm + 10px)", (10 * cssPixelsPerMillimeter) + 10);
    assert_calc_expression("calc(10% + 10px)", (10 * viewportWidthPercent()) + 10);
    assert_calc_expression("calc(1cm + 2in + 1cm + 2px)", (2 * cssPixelsPerInch) + (2 * cssPixelsPerCentimeter) + 2);
    assert_calc_expression("calc(1cm + 2px + 1cm + 2in)", (2 * cssPixelsPerInch) + (2 * cssPixelsPerCentimeter) + 2);
    assert_calc_expression("calc(10% + 10px + 2% + 10pc)", (12 * viewportWidthPercent()) + 10 + (10 * cssPixelsPerPica));
}, "Tests calc() on presentation and non-presentation attr in svgLength");
</script>
